
#include "Channel.h"
#include <Log.h> 
#include "EventLoop.h"
#include <bits/types/struct_itimerspec.h>
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <memory>
#include <sys/timerfd.h>
#include <timewheel.h>

namespace muduo
{
    // ======================TimerTask=============================
    TimerTask::TimerTask(uint64_t id,uint32_t timeout,const Task_func& task_cb):_id(id),_timeout(timeout),_task_cb(task_cb),_cancel(false)
    {}
    TimerTask::~TimerTask()
    {
        if(_cancel == false)_task_cb();
        _release();
    }
    void TimerTask::SetRelease(Release_fun release)
    {
        _release = release;
    } 
    void TimerTask::SetCancel()
    {
        _cancel = true;
    }
    uint32_t TimerTask::Get_timeout()
    {
        return _timeout;
    }
    // ======================TimerWheel:private=============================
    void TimerWheel::RemoveTimer(uint64_t id)
    {
        // 从管理的_timers中通过id寻找，之后删除
        auto iter = _timers.find(id);
        if(iter==_timers.end()) return;
        _timers.erase(id);
    }
    int TimerWheel::CreatetimerFd(){
        // CLOCK_MONOTONIC代表从系统启动到现在的事件，不受手动调整系统时间的影响，flag默认填0
        int timerfd = timerfd_create(CLOCK_MONOTONIC,0) ;
        if(timerfd<0){
            errorlog<<"timerfd create error";
            abort();
        }
        // itimerspec是一个指定定时器超时时间和间隔时间的结构体
        struct itimerspec itime;
        // 第一次超时时间
        itime.it_value.tv_sec=1;
        itime.it_value.tv_nsec=0;
        // 第一次超时后，后续每次超时的间隔
        itime.it_interval.tv_sec=1;
        itime.it_interval.tv_nsec=0;
        timerfd_settime(timerfd, 0, &itime, NULL);
        return timerfd;
    }
    // =======================return int=====
    int TimerWheel::Readtimerfd(){
        uint64_t times;
        int ret = read(_timerfd,&times,8);
        if(ret<0){
            errorlog<<"timefd read error";
            abort();
        }
        return times;
    }
    void TimerWheel::RunTimeTask()
    {
        _tick = (_tick+1) % _capacity;
        // 将vector中对应位置的所有shared_ptr管全部释放掉，对应的引用计数-1，如果引用计数为0，则会自动释放定时器对象。
        _wheel[_tick].clear(); 
    }
    void TimerWheel::RunOnTime(){
        // timerfd执行read回调说明被触发（1s）,触发后将滴答指针向后移动则可将timerfd与时间轮模块结合
        int times=Readtimerfd();
        for(int i=0;i<times;i++){
            RunTimeTask();
        }

    }
    void TimerWheel::AddTimerTaskInLoop(uint64_t id,uint32_t delay,const Task_func& task_cb){
        PtrTask pt(new TimerTask(id,delay,task_cb)) ;
        // 设置定时器销毁时的动作（取消map中对应的键值对）
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
        // 将创建的Ptr对象添加到wheel中
        int pos = (_tick+delay) % _capacity;
        _wheel[pos].push_back(pt);

        _timers[id] = WeakTask(pt);   
    }
    void TimerWheel::TimerRefreshInLoop(uint64_t id){
        auto iter = _timers.find(id);
        if(iter == _timers.end()) return;
        // lock()能直接的到weak_ptr管理的shared_ptr
        PtrTask pt = iter->second.lock();
        uint32_t delay = pt->Get_timeout();
        int pos = (_tick+delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    void TimerWheel::TimerCancelInLoop(uint64_t id){
        auto iter = _timers.find(id);
        if(iter == _timers.end()) return;
        // lock()能直接的到weak_ptr管理的shared_ptr
        PtrTask pt = iter->second.lock();
        if(pt) pt->SetCancel();
    }
    // ======================TimerWheel:pubilc=============================
    TimerWheel::TimerWheel(EventLoop* loop):_loop(loop),_tick(0),_capacity(60),_wheel(_capacity)\
                                        ,_timerfd(CreatetimerFd()),_timerChannel(new Channel(_loop,_timerfd)){
        _timerChannel->Set_read_callback(std::bind(&TimerWheel::RunOnTime,this));
        _timerChannel->EnableRead();
    }
    // 因为可能有多个线程同时对_timer定时器进行操作，所以涉及到线程安全的问题
    // 同样不可能直接对线程加锁，所以将对定时器的操作放到同一个线程中进行
    void TimerWheel::AddTimerTask(uint64_t id, uint32_t delay, const Task_func& task_cb)
    {
        _loop->RunLoop(std::bind(&TimerWheel::AddTimerTaskInLoop,this,id,delay,task_cb));
    }
    void TimerWheel::TimerRefresh(uint64_t id)
    {
        _loop->RunLoop(std::bind(&TimerWheel::TimerRefreshInLoop,this,id));
    }
    void TimerWheel::TimerCancel(uint64_t id)
    {
        _loop->RunLoop(std::bind(&TimerWheel::TimerCancelInLoop,this,id));
    }

    bool TimerWheel::HasTimer(uint64_t id){
        auto iter = _timers.find(id);
        if(iter == _timers.end()) {return false;}
        return true;
    }
}